﻿using System;
using System.Xml;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace openxmlconv
{
    public class OpenXmlWriter
    {
        
        static string wordNs = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
        public static void Write(Document document, string filename)
        {
            string directoryString = Directory.GetCurrentDirectory() +  @"\teste";
            Directory.CreateDirectory(directoryString);
            directoryString = Directory.GetCurrentDirectory() + @"\teste\_rels";
            Directory.CreateDirectory(directoryString);
            directoryString = Directory.GetCurrentDirectory() + @"\teste\word";
            Directory.CreateDirectory(directoryString);

            XmlWriter contentTypes = new XmlTextWriter(@"teste\[Content_Types].xml", System.Text.Encoding.UTF8);
            XmlWriter relations = new XmlTextWriter(@"teste\_rels\.rels", System.Text.Encoding.UTF8);
            XmlWriter contents = new XmlTextWriter(@"teste\word\Document.xml", System.Text.Encoding.UTF8);

            WriteContentTypes(contentTypes);
            WriteRelations(relations);
            WriteDocument(contents, document);

            contentTypes.Close();
            relations.Close();
            contents.Close();

            ZipLib lib = new ZipLib();

            lib.CompressDirectory(Directory.GetCurrentDirectory() + @"\teste", "teste.zip", Directory.GetCurrentDirectory());
        }

        private static void WriteDocument(XmlWriter writer, Document document)
        {
            writer.WriteStartDocument(true);
            writer.WriteStartElement("w", "document", wordNs);

            writer.WriteStartElement("w", "body", wordNs);

            WriteParagraphs(document, wordNs, writer);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }

        private static void WriteRelations(XmlWriter relations)
        {
            relations.WriteStartDocument(true);
            relations.WriteStartElement("Relationships");
            relations.WriteAttributeString("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships");

            relations.WriteStartElement("Relationship");
            relations.WriteAttributeString("Id", "rId1");
            relations.WriteAttributeString("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
            relations.WriteAttributeString("Target", "word/document.xml");

            relations.WriteEndElement();

            relations.WriteEndElement();
        }

        private static void WriteContentTypes(XmlWriter contentTypes)
        {
            contentTypes.WriteStartDocument(true);
            contentTypes.WriteStartElement("Types");
            contentTypes.WriteAttributeString("xmlns", "http://schemas.openxmlformats.org/package/2006/content-types");

            contentTypes.WriteStartElement("Default");
            contentTypes.WriteAttributeString("Extension", "rels");
            contentTypes.WriteAttributeString("ContentType", "application/vnd.openxmlformats-package.relationships+xml");
            contentTypes.WriteEndElement();

            contentTypes.WriteStartElement("Default");
            contentTypes.WriteAttributeString("Extension", "xml");
            contentTypes.WriteAttributeString("ContentType", "application/xml");            
            contentTypes.WriteEndElement();

            contentTypes.WriteStartElement("Override");
            contentTypes.WriteAttributeString("PartName", "/word/document.xml");
            contentTypes.WriteAttributeString("ContentType", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");            
            contentTypes.WriteEndElement();

            contentTypes.WriteEndElement();
        }
        private static void WriteParagraphs(Document document, string wordNs, XmlWriter writer)
        {
            foreach (Paragraph p in document)
            {
                writer.WriteStartElement("w", "p", wordNs);
                if (p.getStyle().getAlignment() == "end")
                {
                    writer.WriteStartElement("w", "pPr", wordNs);
                    writer.WriteStartElement("w", "jc", wordNs);
                    writer.WriteStartAttribute("w", "val", wordNs);

                    writer.WriteString("right");
                    writer.WriteEndAttribute();
                    writer.WriteEndElement();
                    writer.WriteEndElement();
                }
                writer.WriteStartElement("w", "r", wordNs);

                writer.WriteStartElement("w", "rPr", wordNs);
                Style s = p.getStyle();
                if (s != null)
                {
                    if (p.getStyle().getBold())
                    {
                        writer.WriteStartElement("w", "b", wordNs);
                        writer.WriteEndElement();
                    }
                    if (p.getStyle().getItalic())
                    {
                        writer.WriteStartElement("w", "i", wordNs);
                        writer.WriteEndElement();
                    }
                    if (p.getStyle().getUnderline())
                    {
                        writer.WriteStartElement("w", "u", wordNs);
                        writer.WriteStartAttribute("w", "val", wordNs);
                        writer.WriteString("single");
                        writer.WriteEndAttribute();
                        writer.WriteEndElement();
                    }
                    if (p.getStyle().getFontName() != null)
                    {
                        writer.WriteStartElement("w", "rFonts", wordNs);
                        writer.WriteStartAttribute("w", "ascii", wordNs);
                        writer.WriteString(p.getStyle().getFontName());
                       
                        writer.WriteEndAttribute();
                        writer.WriteStartAttribute("w", "hAnsi", wordNs);
                        writer.WriteString(p.getStyle().getFontName());

                        writer.WriteEndAttribute();
                        writer.WriteStartAttribute("w", "cs", wordNs);
                        writer.WriteString(p.getStyle().getFontName());

                        writer.WriteEndAttribute();
                        writer.WriteEndElement();
                    }
                    p.getStyle().getFontSize();

                    writer.WriteStartElement("w", "sz", wordNs);

                    writer.WriteStartAttribute("w", "val", wordNs);

                    writer.WriteString((p.getStyle().getFontSize()*2).ToString());

                    writer.WriteEndAttribute();

                    writer.WriteEndElement();
                    
                }
                writer.WriteEndElement();
                writer.WriteStartElement("w", "t", wordNs);
                //writer.WriteString(p.getText());
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
        /// <summary>
        /// Creates a zip file
        /// </summary>
        /// <param name="zipFileStoragePath">where to store the zip file</param>
        /// <param name="zipFileName">the zip file filename</param>
        /// <param name="fileToZip">the file to zip</param>
        /// <returns>indicates whether the file was created successfully</returns>
        private static bool CreateZipFile(string zipFileStoragePath
            , string zipFileName
            , FileInfo fileToZip)
        {
            return CreateZipFile(zipFileStoragePath
                                , zipFileName
                                , (FileSystemInfo)fileToZip);
        }

        /// <summary>
        /// Creates a zip file
        /// </summary>
        /// <param name="zipFileStoragePath">where to store the zip file</param>
        /// <param name="zipFileName">the zip file filename</param>
        /// <param name="directoryToZip">the directory to zip</param>
        /// <returns>indicates whether the file was created successfully</returns>
        private static bool CreateZipFile(string zipFileStoragePath
            , string zipFileName
            , DirectoryInfo directoryToZip)
        {
            return CreateZipFile(zipFileStoragePath
                                , zipFileName
                                , (FileSystemInfo)directoryToZip);
        }

        /// <summary>
        /// Creates a zip file
        /// </summary>
        /// <param name="zipFileStoragePath">where to store the zip file</param>
        /// <param name="zipFileName">the zip file filename</param>
        /// <param name="fileSystemInfoToZip">the directory/file to zip</param>
        /// <returns>indicates whether the file was created successfully</returns>
        private static bool CreateZipFile(string zipFileStoragePath
            , string zipFileName
            , FileSystemInfo fileSystemInfoToZip)
        {
            return CreateZipFile(zipFileStoragePath
                                , zipFileName
                                , new FileSystemInfo[] 
                            { 
                                fileSystemInfoToZip 
                            });
        }

        /// <summary>
        /// A function that creates a zip file
        /// </summary>
        /// <param name="zipFileStoragePath">location where the file should be created</param>
        /// <param name="zipFileName">the filename of the zip file</param>
        /// <param name="fileSystemInfosToZip">an array of filesysteminfos that needs to be added to the file</param>
        /// <returns>a bool value that indicates whether the file was created</returns>
        private static bool CreateZipFile(string zipFileStoragePath
            , string zipFileName
            , FileSystemInfo[] fileSystemInfosToZip)
        {
            // a bool variable that says whether or not the file was created
            bool isCreated = false;

            try
            {
                //create our zip file
                ZipFile z = ZipFile.Create(zipFileStoragePath + zipFileName);
                //initialize the file so that it can accept updates
                z.BeginUpdate();
                //get all the files and directory to zip
                GetFilesToZip(fileSystemInfosToZip, z);
                //commit the update once we are done
                z.CommitUpdate();
                //close the file
                z.Close();
                //success!
                isCreated = true;
            }
            catch (Exception ex)
            {
                //failed
                isCreated = false;
                //lets throw our error
                throw ex;
            }

            //return the creation status
            return isCreated;
        }

        /// <summary>
        /// Iterate thru all the filesysteminfo objects and add it to our zip file
        /// </summary>
        /// <param name="fileSystemInfosToZip">a collection of files/directores</param>
        /// <param name="z">our existing ZipFile object</param>
        private static void GetFilesToZip(FileSystemInfo[] fileSystemInfosToZip, ZipFile z)
        {
            //check whether the objects are null
            if (fileSystemInfosToZip != null && z != null)
            {
                //iterate thru all the filesystem info objects
                foreach (FileSystemInfo fi in fileSystemInfosToZip)
                {
                    //check if it is a directory
                    if (fi is DirectoryInfo)
                    {
                        DirectoryInfo di = (DirectoryInfo)fi;
                        //add the directory
                        z.AddDirectory(di.FullName);
                        //drill thru the directory to get all
                        //the files and folders inside it.
                        GetFilesToZip(di.GetFileSystemInfos(), z);
                    }
                    else
                    {
                        //add it
                        z.Add(fi.FullName);
                    }
                }
            }
        }
    }

}
